#pragma once

#include<vector>
#include<BWAPI.h>

#include"Unit.h"
#include"Location.h"

using std::vector;

class Squad
{
public:
	Squad()
		:DesicionPoint(0),
		_massComputed(false),
		_lowHp(false)
	{
	}
	void GetMass(Location& answer)
	{
		if(_massComputed)
		{
			answer = _mass;
		}
		else
		{
			answer.X = 0;
			answer.Y = 0;
			for(int whichUnit = 0 ; whichUnit < UnitPointers.size() ; ++whichUnit)
			{
				answer.X += UnitPointers[whichUnit]->GetX();
				answer.Y += UnitPointers[whichUnit]->GetY();
			}
			answer.X /= (float)UnitPointers.size();
			answer.Y /= (float)UnitPointers.size();
			_mass = answer;
			_massComputed = true;
		}
	}
	bool AllDeadOrNoUnit() const
	{
		for(int index = 0 ; index < UnitPointers.size() ; ++index)
		{
			if(UnitPointers[index]->Alive())
			{
				return false;
			}
		}
		return true;
	}
	bool LowHp() const
	{
		return _lowHp;
	}
	void SetLowHp()
	{
		_lowHp = true;
	}
	void Tick(bool& needBranchFlag)
	{
		_massComputed = false;
		int needBranchCount = 0;
		for(int whichUnit = 0 ; whichUnit < UnitPointers.size() ; ++whichUnit)
		{
			//bool unitNeedBranch = false;
			UnitPointers[whichUnit]->Tick(needBranchFlag);
			/*UnitPointers[whichUnit]->Tick(unitNeedBranch);
			if(unitNeedBranch)
			{
				++needBranchCount;
			}*/
		}
		/*if(needBranchCount >= UnitPointers.size())
		{
			needBranchFlag = true;
		}*/
	}
	Custom::Unit* GetNearestUnit(const Location& position) const
	{
		Custom::Unit* answer = NULL;
		float minDistance = 99999.0;
		for(int whichUnitIndex = 0 ; whichUnitIndex < UnitPointers.size() ; ++whichUnitIndex)
		{
			float distanceNow = UnitPointers[whichUnitIndex]->Position.GetDistance(position);
			if(distanceNow < minDistance)
			{
				minDistance = distanceNow;
				answer = UnitPointers[whichUnitIndex];
			}
		}
		return answer;
	}
	Custom::Unit* GetWeakestUnit() const
	{
		Custom::Unit* answer = NULL;
		float minHp= 99999.0;
		for(int whichUnitIndex = 0 ; whichUnitIndex < UnitPointers.size() ; ++whichUnitIndex)
		{
			float hpNow = UnitPointers[whichUnitIndex]->Hp;
			if(hpNow < minHp)
			{
				minHp = hpNow;
				answer = UnitPointers[whichUnitIndex];
			}
		}
		return answer;
	}
	//--
	vector<Custom::Unit*> UnitPointers;
	int DesicionPoint;
private:
	bool _lowHp;
	bool _massComputed;
	Location _mass;
};

class Group
{
public:
	Group()
		:Target(NULL)
	{
	}
	void RealToGroup(const vector<BWAPI::Unit*>& realUnits)
	{
		for(int whichUnit = 0 ; whichUnit < realUnits.size() ; ++whichUnit)
		{
			Units.push_back(Custom::Unit(realUnits[whichUnit]));
		}
	}
	void Clear()
	{
		Units.clear();
		Squads.clear();
		Target = NULL;
		EscapePosition.Set(0.0 , 0.0);
	}
	void ComputeMass(Location& answer)
	{
		answer.X = 0;
		answer.Y = 0;
		int totalWeight = 0;
		for(int unitIndex = 0 ; unitIndex < Units.size() ; ++unitIndex)
		{
			const Custom::Unit& whichUnit = Units[unitIndex];
			if(whichUnit.Alive())
			{
				answer.X += whichUnit.Position.X * whichUnit.Hp;
				answer.Y += whichUnit.Position.Y * whichUnit.Hp;
				totalWeight += whichUnit.Hp;
			}
		}
		answer.X /= (float)totalWeight;
		answer.Y /= (float)totalWeight;
	}
	void MakeSquads()
	{
		Squads.clear();
		Squads.resize(2);
		Squads[1].SetLowHp();
		for(int whichUnit = 0 ; whichUnit < Units.size() ; ++whichUnit)
		{
			if(Units[whichUnit].Alive())
			{
				if(Units[whichUnit].Hp > 100.0)
				{
					Squads[0].UnitPointers.push_back(&(Units[whichUnit]));
				}
				else
				{
					Squads[1].UnitPointers.push_back(&(Units[whichUnit]));
				}
			}
		}
	}
	bool AllDead() const
	{
		for(int whichUnit = 0 ; whichUnit < Units.size() ; ++whichUnit)
		{
			if(Units[whichUnit].Alive())
			{
				return false;
			}
		}
		return true;
	}

	//--
	vector<Custom::Unit> Units;
	vector<Squad> Squads;
	Custom::Unit* Target;
	Location EscapePosition;
};